﻿using System;
using System.Collections.Generic;
using System.Linq;
using Sripirom.ATS.Core.Domain;
using Sripirom.ATS.Core.UnitOfWork;
using Sripirom.ATS.Repository.NH.SessionStorage;
using NHibernate;
using Sripirom.ATS.Core.Querying;
//using Sripirom.ATS.Core.Authentication;
using NHibernate.Criterion;

namespace Sripirom.ATS.Repository.NH.Repositories
{
    public abstract class Repository<T, TEntityKey>
        where T: IAggregateRoot
        {

            private IUnitOfWork _uow;

            public Repository(IUnitOfWork uow)
            {
                _uow = uow;

            }

            public TEntityKey Add(T entity)
            {
               object key = SessionFactory.GetCurrentSession().Save(entity);
               return (TEntityKey)key;
            }

            public void Remove(T entity)
            {
                SessionFactory.GetCurrentSession().Delete(entity);
            }

            public void Save(T entity)
            {
                SessionFactory.GetCurrentSession().SaveOrUpdate(entity);
            }

            public T FindBy(TEntityKey id)
            {
                return SessionFactory.GetCurrentSession().Get<T>(id);
            }

            public IEnumerable<T> FindAll()
            {
                ICriteria criteriaQuery =
                        SessionFactory.GetCurrentSession().CreateCriteria(typeof(T));

                return (List<T>)criteriaQuery.List<T>();
            }
            public IEnumerable<T> FindAll(int index, int count)
            {
                var criteriaQuery = SessionFactory.GetCurrentSession().CreateCriteria(typeof(T));

                return (List<T>)criteriaQuery.SetFirstResult(index).SetMaxResults(count)
                            .SetFetchSize(count).List<T>();
            }
            public Int32 CountAll()
            {
                var criteriaQuery = SessionFactory.GetCurrentSession().CreateCriteria(typeof(T));

                criteriaQuery.SetProjection(Projections.RowCount());
                return (int)criteriaQuery.UniqueResult();
            }

            public IEnumerable<T> FindBy(Query query)
            {
                var criteriaQuery = SessionFactory.GetCurrentSession().CreateCriteria(typeof(T));

                AppendCriteria(criteriaQuery);
                query.TranslateIntoNHQuery<T>(criteriaQuery);

                return criteriaQuery.List<T>();
            }

            public IEnumerable<T> FindBy(Query qurey, int index, int count)
            {
                var criteriaQuery = SessionFactory.GetCurrentSession().CreateCriteria(typeof(T));

                AppendCriteria(criteriaQuery);

                qurey.TranslateIntoNHQuery<T>(criteriaQuery);

                return criteriaQuery.SetFirstResult(index).SetMaxResults(count).SetFetchSize(count).List<T>();
            }
            public IEnumerable<T> FindFiltered(Criterion filter)
            {
                var criteriaQuery = SessionFactory.GetCurrentSession().CreateCriteria(typeof(T));

                Query query = new Query() { QueryOperator = QueryOperator.And };
                query.Add(filter);
                AppendCriteria(criteriaQuery);
                query.TranslateIntoNHQuery<T>(criteriaQuery);

                return criteriaQuery.List<T>();
            }
            public Int32 CountBy(Query qurey)
            {

                var criteriaQuery = SessionFactory.GetCurrentSession().CreateCriteria(typeof(T));
                AppendCriteria(criteriaQuery);

                criteriaQuery.SetProjection(Projections.RowCount());
                return (int)criteriaQuery.UniqueResult();
            }
           

            public virtual void AppendCriteria(ICriteria criteriaQuery)
            {
            }

            public void Flush()
            {
                SessionFactory.GetCurrentSession().Flush();
            }
            public void Evict(T entity)
            {
                SessionFactory.GetCurrentSession().Evict(entity);
            }
        }
    }
